Spring 支持标准的 JDO 2.0 和 2.1 API 的数据访问策略,按照与 Hibernate 同样的支持方式。相应的集成类驻留在org.springframework.orm.jdo
包。
Spring提供 LocalPersistenceManagerFactoryBean
类允许您在一个 Spring 应用上下文定义了一个局部的 JDO 的PersistenceManagerFactory
:
<beans>
<bean id="myPmf" class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean">
<property name="configLocation" value="classpath:kodo.properties"/>
</bean>
</beans>
另外,你可以通过一个 PersistenceManagerFactory
实现类的的实例化来设置 PersistenceManagerFactory
。一个 JDO 的PersistenceManagerFactory
实现类遵循 JavaBean 模式,就像一个JDBC DataSource
的实现类,这是在 Spring 里配置使用是非常合适的。这种设置方式通常支持一个 Spring 定义的JDBC DataSource
,传递给 connectionFactory
。例如,对于开源的 JDO 实现DataNucleus(原名 JPOX )(http://www.datanucleus.org/),下面是PersistenceManagerFactory
实现的 XML 配置:
<beans>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="myPmf" class="org.datanucleus.jdo.JDOPersistenceManagerFactory" destroy-method="close">
<property name="connectionFactory" ref="dataSource"/>
<property name="nontransactionalRead" value="true"/>
</bean>
</beans>
也可以在 Java EE 应用服务的 JNDI 环境中 设置 JDO PersistenceManagerFactory
,通常是通过 JCA 连接器提供包含 JDO 的实现。Spring 的标准中 JndiObjectFactoryBean
或 <jee:jndi-lookup>
可以用来检索和暴露比如PersistenceManagerFactory
。然而,在 EJB 上下文 之外,没有真正的存在于在 JNDI 中保持 PersistenceManagerFactory
:只选择这样的一个设置是一个很好的理由。请参见15.3.6“比较容器管理和本地定义的资源”讨论;那里的论点适用于JDO。
利用注入的 PersistenceManagerFactory
,也可以直接利用平常的JDO API来写 DAO,而无需 Spring 的依赖。以下是相应的 DAO 实现的一个例子:
public class ProductDaoImpl implements ProductDao {
private PersistenceManagerFactory persistenceManagerFactory;
public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
this.persistenceManagerFactory = pmf;
}
public Collection loadProductsByCategory(String category) {
PersistenceManager pm = this.persistenceManagerFactory.getPersistenceManager();
try {
Query query = pm.newQuery(Product.class, "category = pCategory");
query.declareParameters("String pCategory");
return query.execute(category);
}
finally {
pm.close();
}
}
}
因为上面的 DAO 依赖注入模式,它适合在 Spring 容器中,就像在Spring 的 JdoTemplate
中编码:
<beans>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="persistenceManagerFactory" ref="myPmf"/>
</bean>
</beans>
这样的 DAO 主要的问题是,他们总是从工厂获得一个新的PersistenceManager
。为了访问 Spring 管理的事务 PersistenceManager
,需要定义一个TransactionAwarePersistenceManagerFactoryProxy
(包含在Spring 中)在你的目标 PersistenceManagerFactory
面前,然后传递一个那个代理的引用到你的 DAO,如下面的示例:
<beans>
<bean id="myPmfProxy"
class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy">
<property name="targetPersistenceManagerFactory" ref="myPmf"/>
</bean>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="persistenceManagerFactory" ref="myPmfProxy"/>
</bean>
</beans>
你的数据访问代码将收到一个来自 PersistenceManagerFactory.getPersistenceManager()
调用的事务性的PersistenceManager
(如果有)的方法。后者的方法的调用会通过代理,在从从工厂获得一个新的之前它首先检查当前事务性的PersistenceManager
。由于 事务性的PersistenceManager
,任何 close() 的调用将会被忽略。
如果你的数据访问代码总是运行在一个活跃的事务中(或至少与活跃的事务同步),它会安全的忽略 PersistenceManager.close()
的调用。这样整个finally
的块,可以让你的 DAO 实现更加简洁:
public class ProductDaoImpl implements ProductDao {
private PersistenceManagerFactory persistenceManagerFactory;
public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
this.persistenceManagerFactory = pmf;
}
public Collection loadProductsByCategory(String category) {
PersistenceManager pm = this.persistenceManagerFactory.getPersistenceManager();
Query query = pm.newQuery(Product.class, "category = pCategory");
query.declareParameters("String pCategory");
return query.execute(category);
}
}
由于这样 DAO 依来活动的事务,所有建议您通过关闭TransactionAwarePersistenceManagerFactoryProxy
的 allowCreate
标签来强制激活事务:
<beans>
<bean id="myPmfProxy"
class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy">
<property name="targetPersistenceManagerFactory" ref="myPmf"/>
<property name="allowCreate" value="false"/>
</bean>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="persistenceManagerFactory" ref="myPmfProxy"/>
</bean>
</beans>
这种 DAO 风格的主要优势是,它只依赖于 JDO API;不需要引进任何的Spring 类。从非侵入性的角度来说更吸引人,并且对于 JDO 开发人员来说可能会觉得更自然。
然而,DAO 抛出平常的 JDOException
(未检查的,因此不需要声明或捕获),这意味着调用者只能将异常当做是致命的,除非你想依靠 JDO 的异常结构。捕捉乐观锁失败等特殊原因是不可能,除非把调用者与实现策略相关联。取消这交易可能会更容易受应用程序接受,因为基于 JDO 和/或 不需要任何特殊的异常处理。
总之,你可以根据平常的 JDO API 生产 DAO ,他们仍然可以参与 Spring管理事务。这策略会可能会吸引你如果你已经熟悉了 JDO。然而,这样的DAO 抛出平常的 JDOException
,您必须显式地转换为 Spring 的DataAccessException
(如果需要)。
如果你还没有看过 12.5. Declarative transaction management 声明式事务管理强烈建议你看下,获取更多Spring 声明式事务的支持
执行服务的事务操作,使用 Spring 常见的声明式事务功能,举例:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="myTxManager" class="org.springframework.orm.jdo.JdoTransactionManager">
<property name="persistenceManagerFactory" ref="myPmf"/>
</bean>
<bean id="myProductService" class="product.ProductServiceImpl">
<property name="productDao" ref="myProductDao"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="increasePrice*" propagation="REQUIRED"/>
<tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/>
<tx:method name="*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="productServiceMethods"
expression="execution(* product.ProductService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/>
</aop:config>
</beans>
JDO 需要一个活动的事务来修改持久化的对象。非事务性的刷新概念并不存在于 JDO,相对于 Hibernate。为此,你需要为特定的环境设置选择的JDO 的实现。具体来说,你需要设置明确的 JTA 同步,来检测一个活跃的JTA 事务本身。这对于 Spring 的 JdoTransactionManager
执行的本地事务来说是没有必要的,但有必要参与 JTA 事务,不管是由 Spring JtaTransactionManager
驱动 还是 EJB CMT 和普通的 JTA。
JdoTransactionManager
能够使 JDO 事务 JDBC 访问代码f访问同一个JDBCDataSource
,提供注册的 JdoDialect
支持底层的 JDBC Connection
检索。这是默认情况下基于JDBC 的 JDO 2.0实现
作为一个高级功能,JdoTemplate
和JdoTransactionManager
支持自定义JdoDialect
可以传递到JdoDialect
的 bean 属性。在这个场景中,DAO 不接受 PersistenceManagerFactory
的引用,而是一个完整的JdoTemplate
实例(例如,传递到JdoDaoSupport
的属性JdoTemplate
中)。使用JdoDialect
实现,您可以启用 Spring 的高级特性支持,通常特定于供应商的方式:
Connection
,用来暴露基于 JDBC 的 DAOPersistenceManager
,使事务变化对于基于 JDBC 的数据访问代码可见JDOExceptions
向 Spring DataAccessExceptions
的高级转换查看 JdoDialect
的 javadocs 获取更多如果使用 Spring JDO 的细节